//
//  AirportViewModel.swift
//  CitySearch
//
//  Created by guotonglin on 2020/6/3.
//  Copyright © 2020 guotonglin. All rights reserved.
//

import Foundation
import RxCocoa
import RxSwift
import RxDataSources


typealias AirportItemsSection = SectionModel<Int, AirportViewPresentable>


protocol AirportsViewPresentable {
    
    typealias Output = (
        title: Driver<String>,
        airports: Driver<[AirportItemsSection]>
    )
    
    typealias Input = (
        selectAirport: Driver<AirportViewPresentable>, ()
    )
    
    typealias Dependencies = (
        title: String,
        models: Set<AirportModel>,
        currentLocation: Observable<(lat: Double, lon: Double)?>
    )
    
    typealias ViewModelBuilder = (AirportsViewPresentable.Input) -> AirportsViewPresentable
    
    var input: AirportsViewPresentable.Input { get }
    var output: AirportsViewPresentable.Output { get }
}

struct AirportsViewModel: AirportsViewPresentable {
    
    var input: AirportsViewPresentable.Input
    var output: AirportsViewPresentable.Output

    private let bag:DisposeBag = DisposeBag()
    
    
    typealias RouterAction = (airportSelectedRelay: PublishRelay<AirportModel>, ())
    
    private let routerAction: RouterAction = (PublishRelay(), ())
    
    typealias Routing = (citySelected: Driver<AirportModel>, ())
    
    lazy var router: Routing = (citySelected: routerAction.airportSelectedRelay.asDriver(onErrorDriveWith: .empty()), ())
    
    init(input: AirportsViewPresentable.Input, dependencies: AirportsViewPresentable.Dependencies) {
        self.input = input
        self.output = AirportsViewModel.output(input: input, dependencies: dependencies)
        
        self.process(dependencies: dependencies)
    }
}

extension AirportsViewModel {
    static func output(input: AirportsViewPresentable.Input, dependencies: AirportsViewPresentable.Dependencies) -> AirportsViewPresentable.Output {

        let sections = Observable.just(dependencies.models)
            .withLatestFrom(dependencies.currentLocation) { (models: $0, currentLocation: $1) }
            .map({ arg in
                arg.models.compactMap({ AirportViewModel(
                                            usingModel: $0,
                                            currentLocation: arg.currentLocation ?? (lat: 0, lon: 0))
                    }).sorted()
            }).map({
                [AirportItemsSection(model: 0, items: $0)]
            }).asDriver(onErrorJustReturn: [])
        return (
            Driver.just(dependencies.title),
            sections
        )
    }
    
    func process(dependencies: AirportsViewPresentable.Dependencies) {
        self.input.selectAirport
            .map({ [models = dependencies.models] (viewModel) in
                models.filter({ $0.code == viewModel.code }).first
            })
            .filter({
                $0 != nil
            }).map({
                $0!
            })
            .map({ [routerAction] in
                routerAction.airportSelectedRelay.accept($0)
            })
            .drive()
            .disposed(by: bag)
        
    }
}

